/*#####################################
     Project Freedom Bucket


prerequisite
      $yum install gamin-devel ImageMagick
compile
      $g++ test.cpp -lfam -ofreedombucket

User
      $./freedombucket <dir path>


#####################################*/

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <errno.h>


#include<string>
#include<stdexcept>
#include<functional>

#include<unistd.h> // access() , sleep()
#include<signal.h> // signal()

#include <stdlib.h>


#include<list>

#include <fam.h>

using namespace std;

int errno;
bool runFam = false ;

enum {
	ERROR_STAT_FILE = 1 ,
	ERROR_DETERMINE_USER ,
	ERROR_FAM_OPEN ,
	ERROR_FAM_MONITOR
} ;


// wraps strerror(), in case errno hasn't been set
void checkStrerror( int error ){

	if( 0 != error ){
		std::cerr << "System error is: " << strerror( errno ) << std::endl ;
	}

	return ;

}

typedef std::list< FAMRequest* > RequestList ;
RequestList requests ;


int main(const int argc , const char** argv){
	
	
	if( 1 == argc ){
		std::cerr << "Watch a list of files using FAM" << std::endl ;
		std::cerr << "Usage: " << argv[0] << " <file1> [file2 ... fileN]" << std::endl ;
		std::cerr << "(Watches for file changes until you force-quit with ^C.)" << std::endl ;
		std::cerr << "(Specify filenames as absolute paths.)" << std::endl ;

		return(1) ;
	}

	// register a function to handle SIGINT signals
	/*if( SIG_ERR == signal( SIGINT , sighandler_SIGINT ) ){
		std::cerr << "Error: Unable to set signal handler for SIGINT (Control-C)" << std::endl ;
		return( ERROR_REGISTER_SIGHANDLER ) ;
	}*/




	
	const char* toWatch = "/tmp" ;


	// init FAM connection
	FAMConnection* fc = new FAMConnection() ;



	// event data is put here.  This pointer will be reused for each event.
	FAMEvent* fe = new FAMEvent() ;
	


	// connect to the FAM service
	if( 0 != FAMOpen( fc ) ){
		std::cerr << "FAM connectivity test failed: unable to open FAM connection." << std::endl ;
		std::cerr << "(Hint: make sure FAM (via xinetd) and portmapper are running.)" << std::endl ;
		checkStrerror( errno ) ;
		return( ERROR_FAM_OPEN ) ;
	}
	

	

		// register one FAMRequest per watched directory.  The resultant
		// FAMEvent.userdata parameter contains the name of the watched
		// directory.  This is how we can determine the absolute path to
		// the event's target file in the event-handling section.
		std::string* dir = new std::string( argv[1] ) ;
		FAMRequest* fr = new FAMRequest() ;

		std::cout << "Registering directory \"" << *dir << "\" with FAM" << std::endl ;

		try{

			if( 0 != access( dir->c_str() , F_OK ) ){

				throw( std::runtime_error( "directory access problem" ) ) ;

			}

			if( 0 != FAMMonitorDirectory( fc , dir->c_str() , fr , dir ) ){

				throw( std::runtime_error( "problem registering directory with FAM" ) ) ;

			}

		}catch( const std::runtime_error& e ){

			std::cerr << "Unable to access directory." << std::endl ;
			checkStrerror( errno ) ;

			delete( fr ) ;
			delete( dir ) ;

		}

	



	// If we get this far, the service works on this machine.
	// Time to try the other examples.
	std::cout << "FAM connectivity test successful." << std::endl ;
	std::cout << "The remaining examples should work." << std::endl ;
	
	std::cout << "[stop: SIGINT (ctrl-C)]" << "\n\n" << std::endl ;

	std::cout << "[events]" << std::endl ;

	// enable the event loop
	runFam = true ;

	while( runFam ){

		// FAMPending() guarantees there's a waiting event, such that FAMNextEvent()
		// won't block.

		// This is a gratuitous example of FAMPending(): in theory, there would be
		// other (non-FAM) tasks in the event loop.  Given that the loop just calls
		// sleep(), a real app would have used only FAMNextEvent() here.
		
		if( 1 != FAMPending( fc ) ){
			sleep( 2 ) ;
			continue ;
		}


		int rc = FAMNextEvent( fc , fe ) ;

		if( 1 != rc ){
			std::cerr << "FAMNextEvent returned error" << std::endl ;
			continue ;
		}

		std::string* dir = reinterpret_cast< std::string* >( fe->userdata ) ;
		std::string* filename = reinterpret_cast< std::string* >( fe->filename ) ;

		//std::cout << "Event on watched dir \"" << *dir << "\", file \"" << fe->filename << "\" : " ;
		int res = 2;
		std::string command1 = *dir ; //("/bin/bash ./convert_jpg_to_png.sh");
		std::string command2 = fe->filename ;
		std::string command3 = command1 + " " + command2 ;
		std::string command4 = "/bin/bash ./convert_jpg_to_png.sh " + command3 ;
		
		//std::cout<<" =============="<< command4;

		
		
		
		switch( fe->code ){

			case FAMCreated:
				std::cout << "file was created" ;
				
				res = system (command4.c_str());
				//std::cout<<" **** " << command;
				break ;

			default:
				// should only see this in future FAM versions that add new events
				std::cout << "some other event we don't care about" << std::endl ;

		} // switch( fe->code )

		std::cout << " (code " << fe->code << ")" << std::endl ;

	}

	// - - - - - - - - - - - - - - - - - - - -
	// cleanup
	int ix = 2;

	for(
		RequestList::const_iterator ix( requests.begin() ) , stop( requests.end() ) ;
		ix != stop ;
		++ix
	){

		std::cout << "[Cancelling monitor for FAMRequest " << (*ix)->reqnum << "]" << std::endl ;
		FAMCancelMonitor( fc , *ix ) ;

		delete( *ix ) ;

	}

	

	// disconnect from the FAM service
	FAMClose( fc ) ;

	delete( fe ) ;
	delete( fc ) ;

	return( 0 ) ;
	
}
